Kinky World - CHANGELOG b445 v0.8.8

1) Version update
- Hardcoded version aligned to "v0.8.8 (Build 445)".
- "KinkyMod" values:
  - "sRevision = 8"
  - "sBuild = 445"

2) Code-lock cleanup note
- Many entries have been omitted from this changelog because were merely investigations and/or contained method/symbol references not present in the current Source Code (445 v088) source-of-truth state. This is a full revision of the previous changelog that has been redacted to be less redundant and polished as possible.

3) Fertility map-tag naming clarity (settings + trait description STBL update)
- Context from in-game validation:
  - "MapTagFertile" behavior is tied to the "WooHooer" trait ("Loves Sex" in localized UI), and this dependency was not clear in current setting label/description wording.
- Updated settings label metadata (STBL):
  - "Oniki.KinkyMod.OptionSettings.MapTagFertile"
  - "0xCDD79FD84B93FE76"
  - "EN: Loves Sex Trait Fertility Radar (Map)"
- Updated trait description line (STBL):
  - key hash: "0xA3429641C539227F"
  - "EN ORIGINAL: • Prioritizes their partner's satisfaction"
  - "EN NEW: • Sims with this trait can use a fertility radar on the map!"
- Intent:
  - reduce user confusion by explicitly surfacing the "Loves Sex" trait dependency and map-radar purpose in player-facing text.

4) New Pregnancy toggle: "Enable Female Fertility" (default true, first menu item)
- Added a dedicated persistable setting:
  - "EnableFemaleFertility" (default "true")
  - localized option key: "Oniki.KinkyMod.OptionSettings.EnableFemaleFertility"
- UI placement:
  - inserted as first item in "OptionSettingMenuPregnancy".
- Runtime behavior when set to "false":
  - blocks fertile-cycle behavior by skipping follicular -> ovulatory transition.
  - blocks impregnation checks in ovulatory update path.
  - removes/suppresses fertile state artifacts:
    - "KWBuff.Fertile"
    - fertile map tag path ("SimTag" ""Fertile"" / "MapTagFertile" flow)
  - suppresses period-cycle warning popup tied to fertility-facing menstrual messaging.
- Design intent:
  - provide true user-facing fertility OFF behavior without relying on "PregnancyDisabled" semantics.

5) Migration boundary alignment for Build 445 release
- "EnableFemaleFertility" upgrade initialization moved to:
  - "PreviousVersion < 445"
- Rationale:
  - Build 444 is already public and does not include this setting;
  - ensures add-if-missing initialization runs on 444 -> 445 upgrade path.

6) New toggle: "Enable Menstrual Cycle Progression" (pause + sterile cleanup mode)
- Added new persistable setting:
  - "EnableMenstrualCycleProgression" (default "true")
  - localized option key: "Oniki.KinkyMod.OptionSettings.EnableMenstrualCycleProgression"
- Pregnancy menu ordering update:
  - inserted after "ZooPregnancyChance" (EP5 branch) and before "EnableMenstrualCyclePeriod".
- Runtime behavior when set to "false":
  - pauses menstrual phase progression (no phase timer advance outside active pregnancy phase).
  - clears pending reproductive runtime state for sterile behavior:
    - sperm pool ("mSperms")
    - pending impregnation ("mPendingPregnancy")
    - impregnation check timer ("mImpregnationCheckTime")
  - removes fertility/period runtime artifacts:
    - fertile tag path ("SimTag "Fertile"")
    - "KWBuff.Fertile"
    - menstrual-cycle related buffs via existing period cleanup path.
- Safety intent:
  - no invasive legacy flow rewrite;
  - state is paused/cleaned predictably and can resume safely when re-enabled.

7) Fertility OFF hardening ("EnableFemaleFertility = false") - full runtime reset
- Added explicit runtime sterilization on female fertility OFF:
  - clears "mPendingPregnancy"
  - clears sperm pool ("mSperms")
  - resets impregnation timer ("mImpregnationCheckTime")
  - removes fertile tag/buff artifacts ("SimTag "Fertile"", "KWBuff.Fertile")
- Added guard in "AddSperm(...)":
  - sperm is no longer accumulated while "EnableFemaleFertility" is disabled.
- Result target:
  - ON/OFF behaves as true reset toggle without latent pending fertilization state.

8) Pregnancy menu hardcoded order overhaul (UX-first grouping)
- Reordered "OptionSettingMenuPregnancy" to surface prerequisites and cycle controls first:
  - "EnableExternalPregnancy"
  - "PregnancyDisabled"
  - "EnableMenstrualCycleProgression"
  - "EnableMenstrualCyclePeriod"
  - "EnableMenstrualCycleOverride"
  - menstrual cycle age submenus ("Teen", "YoungAdult", "Adult")
- Mid/advanced section now follows:
  - "EnableFemaleFertility"
  - "MapTagFertile"
  - sperm controls ("SpermLifeTime", "SpermFertilization")
  - "ShemaleChance", optional "DroidPregnancy" (EP11), "PregnancyLength"
  - zoo pregnancy family ("Type" + chances, EP5)
- Intent:
  - improve discoverability and reduce contradictory toggle combinations by presenting dependencies earlier in the flow.

9) Positive KW pregnancy toggle migration ("EnableKWPregnancy") with legacy-safe fallback
- Added new source-of-truth setting and UI toggle:
  - "Oniki.KinkyMod.OptionSettings.EnableKWPregnancy"
  - "0x7A1EF763C267400B"
  - "EN: Enable KW Pregnacies"
  - replaces legacy negative UX toggle in menu ("PregnancyDisabled" removed from active UI path).
- Menu order confirmation:
  - now placed at position #2 in "Pregnancy" menu (after "EnableExternalPregnancy").
- Runtime logic migration:
  - conception/cancellation flow in "Womb" now uses "Settings.EnableKWPregnancy".
  - when disabled, KW pregnancy path is blocked/cancelled as before (same behavior, positive semantics).
- Upgrade strategy ("PreviousVersion < 445"):
  - if new key is missing, migrate from legacy by inversion:
    - "EnableKWPregnancy = !PregnancyDisabled"
  - if new key exists, preserve it.
- Backward safety:
  - legacy "PregnancyDisabled" key remains serialized for old-build rollback compatibility;
  - runtime falls back to legacy only when new key is absent.

10) Upgrade migration notice for legacy pregnancy key conversion (STBL-ready)
- Converted migration popup text from hardcoded string to localized STBL key:
  - "Oniki.KinkyMod.ui/notifications/main:pregnancy_toggle_migration_detailed"
  - "Hash: compute in S3PE/FNV64 tool for your STBL workflow"
  - "EN: Legacy setting migration detected:\r"Pregnancy Disabled: {0.String}" (build {1.String})\rconverted to\r"Pregnancy Enabled: {2.String}" (build {3.String})."
- Runtime behavior:
  - message is emitted only when legacy conversion actually runs ("PregnancyDisabled -> EnableKWPregnancy" during upgrade path);
  - payload placeholders:
    - "{0}" = legacy "PregnancyDisabled" value
    - "{1}" = previous build
    - "{2}" = migrated "EnableKWPregnancy" value
    - "{3}" = current build
- One-shot scope:
  - shown once in that load session, then flag is cleared;
  - after save/reload (with no new migration event), the popup does not reappear.

11) Disabled sleep cancel-chain root cause + corrective patch (production-safe)
- Root cause consolidated from forensic analysis:
  - in disabled mode, some saves/lots could keep stale or mixed "BedSleep" definition bindings on instantiated beds;
  - symptom pattern: immediate sleep queue drop ("BedSleep" removed), "CancelExternal"/"HigherPriorityNext", fallback chain ("GetOutOfBed"/"GoHere"), and perceived "soft reset" behavior.
- Corrective patch applied:
  - kept robust disabled-side bed refresh path with broad definition cleanup on world objects ("BedSleep.Definition" family scope);
  - disabled mode now consistently restores EA singleton/tuning path while preserving stronger stale-entry cleanup during runtime transitions.
  - **important:** disabled stability for this case requires the runtime "BedSleep" bridge path to remain active in "KWBedSleep" ("__disabledProbeEnabled = true"), even with probe logging disabled.
- Expected result:
  - "Disabled" no longer drifts into sporadic instant-cancel sleep loops on affected lots/saves.

12) Sleep forensic logger retirement for release + reactivation note
- Sleep forensic diagnostics are now disabled by default for production builds.
- Runtime switch location:
  - "Oniki/Main.cs"
  - "kEnableSleepForensicDiagnostics = false"
- Reactivation procedure (debug-only):
  1. set "kEnableSleepForensicDiagnostics" to "true";
  2. rebuild DLL;
  3. reproduce issue and collect "KWAlwaysDiag_*.xml";
  4. set it back to "false" before release packaging.
- Additional probe path status:
  - disabled BedSleep probe logging in "Oniki.Interactions/KWBedSleep.cs" is kept OFF by default ("__disabledProbeLogging = false").
  - disabled bridge path stays ON by design ("__disabledProbeEnabled = true") because turning it OFF reintroduces the instant-cancel sleep issue on affected saves.

13) Sleep disabled-bridge clarification (design interpretation)
- Why this resolves the bug while staying compatible with Enabled/Disabled design:
  - this path is not used to keep KW gameplay logic active in "Disabled";
  - it is used as a controlled runtime rebinding bridge that forces a clean "BedSleep" definition/singleton handoff on instantiated beds.
- Practical interpretation:
  - "Enabled" remains KW behavior.
  - "Disabled" remains EA behavior.
  - the bridge is a transition/normalization layer that prevents stale mixed bindings from causing "BedSleep" cancel chains ("CancelExternal" -> "GetOutOfBed"/queue drop).

14) Disabled autonomy diagnostics retired for release (toggle retained)
- Disabled the residual periodic autonomy diagnostic stream in production runtime.
- Switch location:
  - "Oniki/Main.cs"
  - "kEnableDisabledAutonomyDiagnostics = false"
- Effect:
  - no continuous "Disabled.Autonomy.Snapshot" debug noise during normal gameplay;
  - troubleshooting path is preserved and can be re-enabled quickly when needed.

15) Pregnancy migration popup rollback to raw bool + settings display alignment
- Rolled back migration popup payload to raw bool string output:
  - "LegacyPregnancyDisabledValue.ToString()"
  - "MigratedEnableKWPregnancyValue.ToString()"
- Updated Settings UI display for pregnancy base/KW toggles to match bool style:
  - "OptionSettingEnableExternalPregnancy"
  - "OptionSettingEnableKWPregnancy"
  - both now render "True" / "False" in row values (instead of "Enabled" / "Disabled").

16) Enabled sleep autonomy fix for invited guests ("StayOver" alignment with EA)
- Root cause confirmed on legacy KW "Enabled" path ("Oniki.Interactions/KWBedSleep.cs", "Definition.CanSleep(...)"):
  - autonomous sleep selection was gated by bed ownership ("BedData.Owner == null || Owner == sim") before EA sleep test.
  - practical effect: invited guests could fail to autonomously choose sleep on assigned beds, even when "VisitSituation.AllowedToStayOver" was active.
- Corrective patch (targeted, low-risk):
  - added explicit guest exception for EA-like behavior:
    - if Sim is current "VisitSituation" guest on that lot and "AllowedToStayOver == true", ownership pre-filter is bypassed;
    - final eligibility still goes through EA "BedSleep.CanSleep(...)".
- Scope:
  - "Enabled" mode only;
  - no change to disabled bridge/runtime fixes;
  - no broad rewrite of KW autonomy policy.

17) Enabled autonomy analysis snapshot (legacy constraints still present)
- Deep-dive conclusion from current troubleshooting wave:
  - KW "Enabled" autonomy remains a legacy-custom decision layer, not a transparent EA pass-through.
- Observed structural constraints (confirmed in code paths analyzed this wave):
  - pre-EA hard gates in some interactions (example: previous bed-owner gate in "KWBedSleep.CanSleep");
  - custom behavior toggles that can diverge from vanilla priorities (example family around "BedSleepOver" in "KWEnterSleeping");
  - high coupling between custom interaction definitions, runtime singleton rebinding, and autonomy selection outcomes.
- Practical release posture (current recommendation):
  - continue with narrow corrective patches on verified regressions;
  - avoid broad autonomy rewrite in this build line;
  - maintain a future backlog item for incremental “EA parity” audits per high-impact interaction family.

18) Energy autonomy forensic trace (Andy-filtered, no behavior change)
- Added deep Energy branch diagnostics in "Oniki.Gameplay/KWAutonomy.cs", filtered to "Andy Graham" only, behind "AutonomyDebugLogging".
- New trace family:
  - "FindBestInteraction(Commodity).EnergyForensic.Start"
  - "...EnergyForensic.Source"
  - "...EnergyForensic.Candidate"
  - "...EnergyForensic.CandidateForensic"
  - "...EnergyForensic.Selected"
  - "...EnergyForensic.NoCandidate"
- Candidate taxonomy introduced for debug readability:
  - "sleep_like"
  - "nap_like"
  - "coffee_like"
  - "other"
- Scope:
  - diagnostics only (no autonomous behavior modification in this section).

19) Energy policy hardening: sleep-only enforcement at serious fatigue
- Added targeted Energy decision rule in "Oniki.Gameplay/KWAutonomy.cs":
  - if Sim has "Exhausted", OR
  - if Sim has any sleep moodlet ("Sleepy"/"Tired"/"Exhausted") AND "Energy <= -10",
  - then autonomy enters "sleep-only" filtering for that decision pass.
- Behavior in sleep-only mode:
  - non-sleep energy candidates ("nap_like", "coffee_like", "other") are rejected;
  - branch retries selection with a dedicated sleep-only pass ("TrySelectSleepOnlyEnergyCandidate(...)");
  - accepted class is only "sleep_like" (still validated by existing pre-queue/route guards).
- Design intent:
  - keep nap/coffee choices in light fatigue windows,
  - force direct bed-oriented recovery when fatigue is already meaningful/critical.

20) Away-from-home base-needs "Go Home" fallback (safe semantic recovery)
- Extended semantic fallback pattern (already used for hunger) to base TS3 needs when no valid candidate is found out-of-home.
- New guard path in "Oniki.Gameplay/KWAutonomy.cs":
  - "TryApplyNeedGoHomeFallback(CommodityKind commodity, string reason)"
  - invoked on "NoCandidate" for need branch when "addToQueue=true".
- Coverage:
  - "Hunger", "Energy", "Bladder", "Hygiene", "Social", "Fun".
- Activation conditions:
  - Sim is on a lot different from home ("LotCurrent != LotHome");
  - need commodity is present on Sim motives;
  - no candidate was selected in current need branch;
  - need has signal via moodlet and/or motive threshold.
- Current motive thresholds:
  - "Hunger" / "Energy" / "Bladder": "<= -10"
  - "Hygiene" / "Social" / "Fun": "<= -25"
- Exclusions/safety:
  - skips service Sims and protected situations ("TrickOrTreatSituation", "DaycareSituation");
  - preserves existing interaction safety gates.
- Action:
  - issues "SimTools.MakeSimGoHome(...)" with explicit trace.
- New trace family:
  - "FindBestInteraction(Commodity).NeedGoHome"
  - includes commodity, lot context (residential/public), motive value, moodlet signal, and reason.

21) Final water/post-dive behavior in release runtime (code-locked)
- Water/post-dive handling is now centered on the core autonomy path ("AutonomyManager" + "KWAutonomy") rather than layered experimental swim-side behavior.
- Current release posture:
  - no forced swim interaction overrides are used as a default strategy;
  - no "sleep-in-water workaround" path is treated as a canonical fix;
  - post-dive recovery decisions are expected to emerge from normal candidate/validation/commit flow.
- Scope clarification:
  - prior edge behavior tied to one save-specific buggy pool investigation is treated as non-general release behavior and is not presented as a universal KW issue.

22) Parallel water controllers rollback (final architecture)
- Investigation-era parallel swim controllers and ad-hoc swim interaction guardrails were rolled back from the main release posture to avoid queue flicker/cancel chains and manual-command interference.
- In current code:
  - swim interaction wrappers ("KWSwimAround", "KWSwimAroundInOcean") run native "base.Run()" behavior;
  - no legacy swim-side motive-pressure forcing remains as the default control model.
- Rationale:
  - autonomy fixes are maintained in single-engine scoring/selection/commit flow, not by competing external controllers.

23) Diagnostics and recovery hooks kept but disabled by default
- Recovery and forensic hooks remain available in code for controlled troubleshooting waves, but are not active in standard runtime.
- Runtime guard:
  - "kEnableAutonomySafetyTimer = false" keeps "OnAutonomyWaterForensicTimer" recovery routines inactive by default.
- Practical release intent:
  - avoid always-on overhead and instability from investigative automation;
  - retain targeted diagnostics/recovery paths as opt-in tooling for exceptional cases.

24) Swim stuck-signature emergency safety ("anti-autonomous-death")
- Added a robust swim-stall detector in "Oniki/Main.cs" to catch cases where autonomous swim transitions remain stuck (including UI-canceled-looking states that remain runtime-active).
- Detection model:
  - tracks a stable stagnation signature ("current" + "head" + queue signature + quantized sim position);
  - triggers only on swim-family tokens ("swim", "dive", "getinpool", "poolladder_getinpool");
  - requires repeated unchanged streak before intervention (anti false-positive threshold).
- Recovery pipeline (one-shot with long cooldown):
  - first pass: cancel swim-family interactions in current/queue to free blocked transition;
  - verify recovery only when both "current" and "head" are no longer swim-family;
  - if still stuck, trigger emergency fallback "Reset Sim" ("SetObjectToReset") using the same reset path already exposed by KW debug command flow.
- New telemetry ("KW-WATER-RECOVERY"):
  - "event=stuck_swim_head_detected"
  - "event=stuck_swim_head_recovered"
  - "event=stuck_swim_head_failed_then_reset"
- Safety intent:
  - prevent prolonged autonomous lock states near pools that can block all subsequent survival actions and cause avoidable autonomous deaths.

25) Anti-stall detector extension: "no progress + queue churn" (water + on-foot)
- Extended the emergency anti-stall logic in "Oniki/Main.cs" beyond swim-only stagnation:
  - now detects "no real progress" loops where "current" and sim position remain effectively unchanged while queue content keeps changing/flickering.
- Detection model:
  - no-progress signature: "current + quantized position";
  - churn signal: queue signature changes while no-progress signature stays stable;
  - intervention requires both thresholds (streak + churn) to avoid false positives.
- Recovery order:
  - cancel autonomous current/queued interactions first (soft recovery);
  - verify runtime state change ("current/head/queue") after cancellation;
  - emergency "Reset Sim" fallback only when risk context exists (swim-family lock or critical-need pressure).
- Logger coverage for validation:
  - "event=no_progress_churn_detected"
  - "event=no_progress_churn_recovered"
  - "event=no_progress_churn_failed"
  - "event=no_progress_churn_failed_then_reset"
- Safety intent:
  - cover both pool-side and on-foot flicker loops where interactions appear/disappear without actual state advancement,
  - reduce silent autonomous deadlocks that can escalate into survival failures.

26) Temporary performance isolation: autonomy safety timer disabled
- For profiling/validation isolation, "OnAutonomyWaterForensicTimer" runtime scheduling is temporarily disabled in "Oniki/Main.cs".
- Implementation details:
  - added hard gate "kEnableAutonomySafetyTimer = false";
  - alarm scheduling is skipped when gate is disabled;
  - timer handler includes early-return guard as defensive no-op.
- Effect in this test configuration:
  - these periodic recovery checks do not run:
    - "TryRecoverNoProgressQueueChurn"
    - "TryRecoverStuckSwimHead"
    - "TryRequeueIdleActorAutonomy"
    - "TryRecoverPostDiveSwimStale"
- Purpose:
  - measure perceived save/load and runtime smoothness without safety-timer overhead, then compare with re-enabled configuration.

27) "KWRunAutonomy" migration/default rollback to non-forced behavior
- Removed forced-ON migration behavior and removed dedicated RunAutonomy migration popup.
- Current policy:
  - no forced change to existing serialized user value on upgrade;
  - if key is missing in migration block, initialize conservatively to "false";
  - fresh/reset defaults initialize "KWRunAutonomy" to "false".
- Rationale:
  - observed gameplay remained broadly stable in current test wave even with RunAutonomy disabled when broader safety fixes are present;
  - preserve user control and avoid auto-overriding preference during migration.

28) RunAutonomy deep-dive refactor ("true/false" alignment + strict EA autonomy compliance)
- Removed the temporary "autonomyRestricted" bypass in "Oniki.Gameplay/AutonomyManager.cs".
  - behavior restored to strict EA policy: when EA autonomy restrictions are "Off/None" for a Sim, KW does not execute need-busy override for that Sim in that tick.
- Refactored "TryProcessNeedWhileBusy(...)" result contract:
  - no longer reports the tick as handled when need candidate resolution fails;
  - now returns "false" on "candidate_not_found", allowing normal fallback path to continue instead of dead-looping in handled-without-progress state.
- Added forensic trace markers for busy-override no-progress exits:
  - "reason=need_busy_override_candidate_not_found" (moodlet branch and water-emergency branch).
- Unified moodlet need pipeline in "Oniki.Gameplay/KWAutonomy.cs" across "KWRunAutonomy=true/false":
  - introduced shared moodlet-branch evaluator for "Bladder", "Energy", "Hunger";
  - shared checks now run identically for both modes ("user_cancel_need_cooldown", "post_dive_need_grace", candidate selection trace);
  - "KWRunAutonomy=false" still preserves its intentional narrower scope (no "WorkMotive" pass).
- Expected outcome:
  - fixes no longer depend on divergent duplicated branch code,
  - reduced risk of hot-tub/sleep starvation loops caused by handled-without-enqueue paths,
  - no hidden override of EA “no free will” policy.

29) Need-delta requeue + household starvation recovery hardening (disabled-friendly)
- Added per-Sim need signature tracking and dirty-flag requeue in "Oniki.Gameplay/AutonomyManager.cs":
  - dirty signature tracks base-need pressure changes (bladder/hunger/energy + water emergency signal);
  - dirty actors are re-enqueued with per-cycle budget and per-Sim throttle.
- Added round-robin household recovery candidate strategy:
  - prioritizes dirty critical -> dirty -> critical -> fallback selectable;
  - avoids repeatedly selecting the same household Sim during starvation recovery loops.
- Result target:
  - reduce "processed too late" cases for busy Sims when needs change between autonomy passes.

30) Need detection migration to motive thresholds (base needs) + retune
- Base need detection for "Bladder", "Hunger", "Energy" now uses motive values as source-of-truth (instead of relying on moodlet/buff availability timing).
- Active thresholds:
  - warning: "<= -45"
  - critical: "<= -70"
- Water emergency remains buff-driven:
  - "Drowning"
  - "Fatigued"
- Historical note:
  - this was an intermediate stage of the "b445" investigation line;
  - later sections ("93", "94") supersede water safety with motive-aware hardening and enhanced hard-cancel alignment.
- Result target:
  - stable trigger behavior even when moodlet presentation is delayed/inconsistent in long-lived saves.

31) Busy-need preemption expansion (warning-level on low-criticality interactions)
- Added warning-level preempt path for low-criticality/leisure current interactions (for example relax/hot-tub/read/computer families).
- Policy:
  - warning preempt applies only to low-criticality interaction families;
  - critical preempt remains available for life-preserving escalation (for example severe hunger/sleep pressure).
- Safety guards preserved:
  - EA autonomy hard-off levels are respected (no forced intervention when explicitly disabled by player options).

32) World-load preempt safety gate switched to real-time grace (5 seconds)
- Preempt logic now applies a short world-load grace in real time:
  - "5" seconds from world-load enqueue phase.
- Rationale:
  - avoid aggressive cancellation during unstable post-load transition windows;
  - improve reproducibility for test sessions (time-based, not sim-speed/tick dependent).

33) Cancel path simplification to EA-like queue cancel behavior (safety-first)
- Refined need-preempt cancel flow to mirror user queue cancel intent:
  - primary: "UserCanceled" + "CancelInteraction(...)"
  - fallback: "CanceledByScript" + "CancelInteraction(...)"
- Removed posture-forcing fallback from need preempt path:
  - no "CancelPosture(...)" in warning/critical need preempt chain.
- Result target:
  - reduce risk of world/scene instability from aggressive posture interruption while preserving emergency cancel intent.

34) Autonomy debug logging compact mode (state-change + 15s heartbeat)
- Added compact emission gate for noisy autonomy channels:
  - "KW-NEEDFIX-FORENSIC"
  - "KW-AUTONOMY-TRACE"
  - "KW-AUTONOMY-QUEUE"
  - "KW-AUTONOMY-RECOVERY"
  - "KW-AUTONOMY-CENSUS"
- Emission policy:
  - log immediately on payload change;
  - otherwise emit heartbeat at most every "15" seconds (real time) per key.
- Payload normalization updates included for census/recovery to reduce per-line entropy and file growth.

35) Settings UI cleanup: submenu containers now display "..." instead of "Enabled/Disabled"
- Container rows were normalized to avoid misleading value text on menu entries that open submenus.
- Updated container display style for:
  - "OptionSettingMenuDialogsNotifications"
  - "OptionSettingMenuMenstrualCyclePeriod"
  - "OptionSettingMenuRape"
  - "OptionSettingMenuPeepingTom"
  - "OptionSettingMenuFlasher"
  - "OptionSettingMenuCallgirlService"
  - "OptionSettingMenuHighSchool"
  - "OptionSettingMenuRapeService"
  - "OptionSettingMenuStrayPetService"
  - "OptionSettingMenuZooLover"

36) Settings UI structure: new "Advanced" container for maintenance actions
- Added dedicated submenu class:
  - "Oniki.UI.OptionSettingMenuAdvanced"
- Main "OptionSettings" now routes maintenance/risky actions into "Advanced":
  - "Import Settings"
  - "Export Settings"
  - "Uninstall Kinky World" (shown only when "HasBeenEnabled")
  - "Reset All Settings" (shown only when "Settings.Enabled")
- Goal:
  - reduce accidental clicks in compact rows on modern displays;
  - keep gameplay-facing options visually separated from maintenance actions.

37) Dialogs menu refactor: dedicated class split with compatibility alias
- Introduced dedicated class/file for the merged submenu:
  - "Oniki.UI.OptionSettingMenuDialogsNotifications"
- Kept legacy compatibility alias:
  - "Oniki.UI.OptionSettingMenuDialogs : OptionSettingMenuDialogsNotifications"
- "OptionSettings" now uses the dedicated class explicitly, preserving existing submenu behavior while improving code clarity for future maintenance.

38) Build safety support for future settings/menu class additions
- "build_experimental.ps1" hardened for safe UI class expansion:
  - auto-includes new "Oniki.UI/*.cs" sources (allowlisted scope);
  - excludes non-source/system dirs ("bin", "obj", ".git", ".cursor", "packages", "node_modules", ".vs");
  - blocks suspicious secret-like path names (".env", "secret", "token", "password", "apikey", etc.).
- Added mandatory source-encoding guard:
  - build now fails early if a source contains NUL bytes or UTF-16/UTF-32 BOM;
  - accepted baseline for new sources: UTF-8/ASCII compatible encoding.
- Practical result:
  - future new settings containers/classes can be added as separate ".cs" files safely and predictably.

39) Safety timer handlers decoupled from "Settings.Enabled" (runtime-note)
- Removed "Settings.Enabled" early-return gates from:
  - "Main.OnAutonomyWaterForensicTimer()"
  - "Main.OnSwimSafetyTimer()"
- Final runtime posture in this build:
  - handlers are state-agnostic (same code path for Enabled/Disabled),
  - but periodic scheduling for these timer-driven recoveries remains disabled/off by default in current configuration.
- Clarification:
  - this means timer-based recovery families are currently not running continuously;
  - core autonomy safety logic in "AutonomyManager" / "KWAutonomy" remains the active baseline path.
- Rationale:
  - keep timer paths ready for controlled reactivation in targeted troubleshooting waves,
  - while avoiding always-on overhead/aggressive recovery behavior in normal release runtime.

40) Post-dive grace/stabilizer block fully removed (final runtime simplification)
- Removed post-dive grace activation and related busy-need grace skips:
  - deleted "AutonomyManager.ActivatePostDiveSleepGrace(...)"
  - deleted "AutonomyManager.IsPostDiveSleepGraceActive(...)"
  - removed "need_busy_override_post_dive_need_grace_active" decision path
- Removed post-dive swim stabilizer branch from "KWAutonomy":
  - deleted "TryQueuePostDiveSwimStabilizerOnly()" and associated helper methods
  - removed "post_dive_grace_swimaround_only" flow from "FindBestInteraction()"
- Practical final posture:
  - no dive-specific grace-delay layer is active in autonomy decision flow;
  - no extra KW-injected post-dive "SwimAround" stabilizer path remains.

41) Water safety hardening in "KWAutonomy" (fallback-None gate bypass fix)
- Legacy baseline clarification:
  - "b444 v087" and earlier did not include this safety architecture;
  - robust motive/moodlet water guardrails are part of "b445" investigation/refactor line.
- Root cause confirmed from runtime traces:
  - in early "b445" safety implementation, water emergency gate was evaluated, but "QueueVerify" social retarget/fallback could still rewrite candidate to water interactions ("GetInPool"/"SwimAround"/"Dive") before final commit.
- Fix implemented in "Oniki.Gameplay/KWAutonomy.cs":
  - added final post-"QueueVerify" sanitization step immediately before "ConsiderPerformingAutonomousAction(...)";
  - when water emergency is active ("Drowning"/"Fatigued"/fatigue danger), pool/gym candidates are forcibly nulled even if produced by retarget/fallback.
- Added compact forensic marker for candidate mutation chain:
  - "FindBestInteraction(Commodity).QueueVerify | candidate_transition"
  - payload includes "preCandidate -> postCandidate -> finalSanitized".
- Fatigue motive policy in "KWAutonomy" updated for proactive base safety:
  - danger threshold: "-70"
  - release threshold: "-50"
  - intent: block unsafe water proposals before late moodlet-only emergency windows.

42) "Enhanced Basic Autonomy" water-cancel policy realignment (hard-cancel only)
- Design alignment applied in "Oniki.Gameplay/AutonomyManager.cs":
  - Enhanced mode is now a strict script-cancel safety layer, not a second full release/latch controller.
- New enhanced cancel trigger:
  - "Fatigue <= -80" (hard threshold), plus existing hard buff overrides ("Drowning" / "Fatigued") in pool-water context.
- Removed release/latch complexity from Enhanced path:
  - no enhanced-side fatigue release hysteresis logic remains.
- Runtime effect:
  - base autonomy handles normal water exit/no-reentry behavior;
  - Enhanced only force-cancels when actor is still in unsafe water state (hard backup policy).

43) New Sex option: post-WooHoo arousal cooldown (rotating minutes)
- Added a single rotating setting under "Sex" (below "Sex Sequence Max Duration (minutes)"):
  - runtime key: "PostWooHooArousalCooldownEnabled"
  - values: "Disabled / 30 / 60 / 90" (default "30")
- Runtime behavior:
  - on real WooHoo completion, starts a per-Sim cooldown window;
  - while active, positive "STArousal"/"LTArousal" gains are blocked for that Sim.
- STBL documentation (required triplet):
  - "Oniki.KinkyMod.OptionSettings.PostWooHooArousalCooldownEnabled"
  - "0xA8C2E97346638FE5"
  - "EN: Post WooHoo Arousal Cooldown (minutes)"

44) Dialogs/Notifications reliability pass ("FeedbackLevel" live + single "ChanceToNotify" roll)
- "UITools" feedback routing now reads "FeedbackLevel" from current settings at runtime (live), instead of relying on stale static cached value during session.
- Removed double random gate on one notification path:
  - "FeedbackNotify(SimDescription, SimDescription, ...)" no longer applies "ChanceToNotify" before delegating;
  - probability is now evaluated once in the downstream feedback method, avoiding unintended "p^2" effective rate.
- Added small guardrails for null/selected-actor checks in feedback notify paths to reduce edge-case noise without changing intended UX flow.

45) Sim pie menu redesign pass ("Kinky World..." + "Debug..." reorganization)
- Main-menu structure update for Sim-click interactions:
  - kept top-level player actions ("Settings", "Reset Sim", "Set Physical Attractiveness");
  - introduced/used "Advanced..." as container for non-core maintenance/customization paths.
- Moved the following groups under "Kinky World... > Advanced...":
  - "Body Selector..."
  - "Outfits..."
  - "Uniforms..."
  - "Offsets..."
- "Cancel Interaction" moved from "Debug..." to main "Kinky World..." level and is now visible with "DebugMode" both OFF/ON (still requires KW enabled, non-autonomous context).
- "AlwaysAccept" moved from "Debug..." to main "Kinky World..." level while preserving debug gate behavior:
  - visible only when "DebugMode = ON".
- "Set CAS properties" / "Get CAS properties" moved into "Kinky World... > Debug...":
  - visibility condition unchanged ("DebugMode = ON" only).
- "Get Naked" ("Sim_GetNaked") promoted from "Debug..." to main "Kinky World..." level:
  - now visible with "DebugMode" both OFF/ON;
  - existing target constraints remain (human, age/context checks, etc.).
- "States..." submenu ("SetState_Normal" / progressive "SetState_Horny") promoted from "Debug..." to main "Kinky World..." level:
  - now visible with "DebugMode" both OFF/ON;
  - keeps current runtime behavior and progression logic.

46) Debug menu information grouping: new "Infos..." container
- Added a dedicated information submenu under debug path:
  - "Kinky World... > Debug... > Infos..."
- Moved informational/diagnostic readout actions into "Infos...":
  - "Show WooHoo infos"
  - "Show Interaction"
  - "Show Infos"
  - "Show Attractions"
  - "Get WooHoo History"
  - "Dump CommodityInteraction Map"
- Gate behavior preserved:
  - all moved interactions remain available only when "DebugMode = ON" (same runtime test conditions as before).

47) "States..." unification at main "Kinky World..." level
- Removed duplicate debug-side "States..." branch and unified state tools into the already promoted main container:
  - target path now: "Kinky World... > States..."
- Moved into the unified always-visible "States..." container:
  - "Set Menstrual Phase"
  - "Set Period Protection Dirty"
  - "Set/Remove Virgin flag"
- Gate policy update for these three interactions:
  - removed strict "DebugMode = ON" requirement;
  - kept existing runtime constraints (KW enabled, non-autonomous, and interaction-specific target checks).

48) New debug grouping: "Kinky World... > Debug... > Tools..."
- Added a dedicated tools submenu under debug path:
  - "Kinky World... > Debug... > Tools..."
- Moved utility/maintenance debug actions into "Tools...":
  - "Set CASP Properties"
  - "Get CASP Properties"
  - "Repair towel mapping"
  - "Propagate Hair Style"
  - "Equip Prop"
  - "Clean Alarms"
- Gate behavior preserved:
  - all moved interactions keep their existing "DebugMode = ON" visibility logic and prior test conditions.

49) "Abiti completi..." container aligned under "Advanced..." (full set)
- Finalized container hierarchy for outfits-debug tooling:
  - "Kinky World... > Advanced... > Abiti completi..."
- Ensured the full existing "Abiti completi..." set is under "Advanced..." (not split across top-level and advanced):
  - includes "Outfit Infos", "Add Underwear to All Outfits", "Remove All Underwear", "Clean Outfits", and related entries already bound to that container.
- Gate behavior preserved:
  - visibility remains tied to existing "DebugMode = ON" logic for debug-scoped entries.

50) "Abiti completi..." visibility normalization (remove "DebugMode" gating only)
- Removed strict "DebugMode = ON" requirement from the interactions inside:
  - "Outfit Infos"
  - "Add Underwear to All Outfits"
  - "Remove All Underwear"
  - "Remove All Pubic Hair"
  - "Clean Outfits"
- Kept all other runtime constraints unchanged:
  - KW enabled
  - non-autonomous context
  - target/species/age/gender/SimData validity checks where applicable
- Result:
  - "Kinky World... > Advanced... > Abiti completi..." now shows the maximum valid option set regardless of debug toggle, while still respecting normal target constraints.

51) Join permission fix: selectable household override when NPC is current WooHoo master
- Restored join-request usability for active-household Sims during NPC-initiated loops without opening broad NPC spam paths.
- Applied in both join entry points:
  - "Oniki.Interactions.WooHooJoin"
  - "Oniki.Interactions.WooHooJoinInstance"
- New effective rule:
  - keep master-only behavior as default;
  - allow non-master join request when:
    - current WooHoo master is non-selectable (NPC-side owner), and
    - requester Sim is selectable (active household side).
- All existing join safety filters remain unchanged (stage compatibility, jealousy/privacy, room checks, species/incest/zoolover gates, cooldowns, etc.).

52) SuperHorny/HyperHorny behavior alignment + debug instrumentation
- Added/updated dedicated autonomy diagnostics to distinguish:
  - standard commodity-driven autonomy decisions ("FindBestInteraction(Commodity)"),
  - dedicated SuperHorny try-flow path ("TryWooHooSuperHorny").
- Added explicit SuperHorny-flow trace channel events:
  - "[KW-SUPERHORNY-FLOW] phase=Enter/PopupChoice/PopupHandled/PopupSoloRelief/QueueInviteToWooHoo/QueueJoinInstance/QueueWooHooSequence/Exit/Exception".
- Added debug-only per-session toggle for deterministic testing:
  - "Kinky World... > Debug... > Permanent HyperHorny".
  - Session-only flag (no save persistence) with autonomy log events:
    - "[KW-PERM-HYPER] phase=Toggle"
    - "[KW-PERM-HYPER] phase=Enforce".
- Important correction in permanent-hyper enforcement:
  - removed forced high timeout reset from debug enforcement path to avoid suppressing timeout-driven callback opportunities.

53) SuperHorny forced try-flow policy update (toggle semantics)
- "SuperHornyDecisionPopupEnabled" now acts as a compatibility behavior switch:
  - when "true", dedicated "TryWooHooSuperHorny" flow is bypassed;
  - timeout callback path in "BuffSuperHorny" also bypasses dedicated try trigger;
  - runtime behavior remains driven by normal autonomy commodity scoring (no dedicated force path).
- Result target:
  - avoid brittle/rare timeout-only popup forcing and rely on stable commodity-based autonomy behavior.

54) STBL/changelog setting mapping for SuperHorny behavior toggle
- "Oniki.KinkyMod.OptionSettings.SuperHornyDecisionPopupEnabled"
- "0xD663A7D81464FF79"
- "EN: Hyper Horny Doesn't Force Action"

55) Commodity behavior clarification (SuperHorny vs HyperHorny)
- "SuperHorny" influence was already present in commodity/scoring through arousal/motive pressure and acceptance difficulty shaping.
- "HyperHorny" now also has explicit autonomy-branch pressure integration in "KWAutonomy" need override path ("CommodityKind" WooHoo) in this wave.
- Practical interpretation:
  - fragile area was primarily the dedicated timeout-triggered try-flow reliability,
  - not the existence of commodity influence itself.

56) 2026-04-09 - Announce Notifications container + audience/chance controls
Files:
- Oniki.UI/OptionSettingMenuDialogsNotifications.cs
- Oniki.UI/OptionSettingAnnounceLevel.cs
- Oniki/AnnounceLevels.cs
- Oniki/Settings.cs
- Oniki/UITools.cs
- Oniki.Gameplay/WooHooInstance.cs
- Oniki.Interactions/WooHooJoinInShower.cs
- Oniki.Interactions/WooHooMasturbatingSimOnAllFours.cs
- Oniki.Interactions/RapeSim.cs
- Oniki.Interactions/MountSimOnAllFours.cs

.1 UI structure
- Added new submenu in "Dialogs & Notifications":
  - "Announce Notifications"
- Moved/organized announce options into this submenu:
  - "AnnounceLevel"
  - "AnnounceChance"
  - "AnnounceType"

.2 New settings (default values)
- "AnnounceChance" (float, 0..100), default "100"
- "AnnounceAudience" (enum "AnnounceAudience"), default "Everything"
  - "None"
  - "Household"
  - "Everything"

.3 Runtime routing change
- Added "UITools.Announce(...)" as the announce gateway:
  - applies "AnnounceAudience" filter
  - applies "AnnounceChance" probability
  - then delegates to legacy "GameMessage(...)" rendering
- Rewired announce callsites in WooHoo/related interactions from direct "GameMessage(...)" to "Announce(...)".
- "GameMessage(...)" itself remains available and unchanged for non-announce system messages.

.4 STBL keys for newly added announce controls
- "Oniki.KinkyMod.OptionSettings.MenuAnnounceNotifications.Label"
- "0x4A477CF1F5BA7537"
- "EN: Announce Notifications"

- "Oniki.KinkyMod.OptionSettings.AnnounceChance"
- "0x3938E12DA62422CA"
- "EN: Chance of AnnounceLevel"

- "Oniki.KinkyMod.OptionSettings.AnnounceType"
- "0x68D465C7E2A89A92"
- "EN: Type of AnnounceLevel"

------------------------------------------------------------
57) Settings UX renewal (consolidated, non-redundant)
------------------------------------------------------------

- "OptionSettings" navigation was restructured to reduce misclick risk and separate gameplay options from maintenance/debug operations.
- Maintenance actions were grouped under "Advanced" (import/export/uninstall/reset scope).
- Submenu container rows were normalized to "..." style instead of misleading boolean-like values.
- Dialogs/notifications paths were reorganized in dedicated containers (including announce/feedback grouping).
- Sim-click menu layout was flattened for common actions and moved specialized/debug tools into clearer nested paths ("Advanced", "Debug", "Infos", "Tools").
- Goal of the whole UX wave:
  - make setting discovery faster,
  - reduce contradictory toggles placement,
  - keep risky actions away from everyday gameplay toggles.

------------------------------------------------------------
58) Autonomy rewrite baseline (before/independent of "KWRunAutonomy")
------------------------------------------------------------

- The "b445" line reworked autonomy with a root-cause posture in score/select/commit flow, not with broad external forcing.
- Architecture direction validated by "Autonomy investigation":
  - queue lifecycle existed,
  - dominant failures came from candidate quality/validation/commit visibility,
  - not from a single "queue never runs" condition.
- Core rewrite focus:
  - strengthen candidate validation and queue-commit verification,
  - remove false-success outcomes,
  - keep fallbacks deterministic and traceable.
- Distribution policy remains:
  - "KWRunAutonomy" stays "false" by default for this line,
  - stability comes from hardened baseline flow + safeguards rather than forcing full KW-run mode.

------------------------------------------------------------
59) "Enhanced Basic Autonomy" (hard-safety layer)
------------------------------------------------------------

- "EnhancedBasicAutonomy" is explicitly treated as a constrained safety layer, not as a second full controller.
- Policy alignment:
  - hard-cancel intervention only on true danger contexts (not broad latch/release orchestration),
  - preserves main autonomy ownership in regular situations.
- Water-risk alignment in this release line:
  - emergency cancellation remains a backup path in unsafe water states (fatigue/buff danger), not a permanent override mode.

------------------------------------------------------------
60) Idle/emergency fixes and "Autonomy investigation" outcomes
------------------------------------------------------------

- Investigation-driven fixes were applied on concrete failure signatures:
  - social "false success" with empty queue after perform,
  - idle loops with no committed follow-up,
  - unstable water-transition windows,
  - missing effective need recovery in some edge contexts.
- Implemented hardening families include:
  - post-queue commit verification and safe failover,
  - anti-loop cooldown/dedupe behavior for repeated failing candidates,
  - deterministic fallback handling for unresolved need branches,
  - selective emergency guardrails with reduced log noise and clearer forensic markers.
- External parallel swim controllers were retired from release posture where they caused regressions (flicker/cancel chains/manual interference).
- Final rule adopted from investigation:
  - patch root cause in candidate generation, validation, and commit visibility,
  - avoid broad timer-driven forcing as default behavior.

------------------------------------------------------------
61) New settings delta verified vs "Build 444 v0.8.7" baseline
------------------------------------------------------------

Verified in "Oniki/Settings.cs":
- Present in current "Build 445 v0.8.8" source and not present in "Build 444 v0.8.7" baseline:
  - "SuperHornyDecisionPopupEnabled"
  - "AnnounceChance"
  - "AnnounceAudience"
  - "PieMenuLogging"
  - "EnableGlobalBuffer"
  - "LogKWSaveLoadProfile"
  - "STCLogging"
  - "FirstPersonLogging"
  - "EnableCameraModeExperimental"
  - "GenderFreeMasturbateOnAllFours"
  - "UnifiedKinkyTraitsMigration445Done"
  - "DebugTraits"
  - "PostWooHooArousalCooldownEnabled"
  - "EnhancedBasicAutonomy"

- Present in both "Build 444 v0.8.7" and "Build 445 v0.8.8" (kept/refined in this line):
  - "KWRunAutonomy"
  - "EnableKWPregnancy"
  - "EnableFemaleFertility"
  - "EnableMenstrualCycleProgression"

Specific requested toggle (explicit):
- "GenderFreeMasturbateOnAllFours" is a dedicated separate setting key in "445", used by "Oniki.Interactions/MasturbateOnAllFours.cs" to bypass male-only trait gate when enabled.

------------------------------------------------------------
62) Camera Mode experimental (explicit coverage)
------------------------------------------------------------

- Added dedicated gate setting:
  - "EnableCameraModeExperimental"
- Experimental camera interactions in "Oniki.Interactions.Debug/Sim_DumpSMC.cs" are guarded by that setting.
- Companion logging gate:
  - "FirstPersonLogging"
  - logging path also respects global buffer state ("Log.IsGlobalBufferEnabled()").
- UX/runtime guardrails in this path include:
  - safe user notifications for incompatible camera state transitions,
  - debug-gated behavior to avoid accidental always-on impact.

------------------------------------------------------------
63) Pregnancy & Menstrual Cycle renewal (full block)
------------------------------------------------------------

- Core pregnancy semantics were modernized around positive enable-state:
  - "EnableKWPregnancy" as active source-of-truth,
  - compatibility handling for legacy negative key ("PregnancyDisabled") on migration.
- Fertility and cycle controls received dedicated runtime-safe toggles:
  - "EnableFemaleFertility"
  - "EnableMenstrualCycleProgression"
- Runtime hardening in "Womb"-side flow:
  - fertility-off behavior blocks fertile progression/impregnation path,
  - cycle-off behavior pauses progression and clears vulnerable reproductive transient state where applicable.
- Player-facing cleanup:
  - pregnancy menu ordering revised for dependencies first,
  - contradictory combinations reduced by placement and semantics.
- Delta note vs "Build 444 v0.8.7":
  - base keys exist in the "Build 444 v0.8.7" line,
  - "b445" line consolidates migration semantics, UX ordering, and stricter runtime cleanup behavior.

------------------------------------------------------------
64) "KWPhotograph" persistence fix (save-reload loss prevention)
------------------------------------------------------------

- Fixed early-destroy behavior in "KWPhotograph.PostLoad()" that could remove valid photos during owner rebinding windows.
- New persistence posture:
  - no immediate deletion on unresolved owner in early load phase,
  - stale orphan purge only for clearly unresolved/inactive old entries,
  - owner validation accepts phone-parent sim recovery path when direct owner bind is late.
- Goal:
  - keep valid KW photos available after save/load while still cleaning true stale orphans.

------------------------------------------------------------
65) Performance & safety wave (Uninstall -> parser -> global buffers)
------------------------------------------------------------

- Runtime safety from disable/uninstall path:
  - controlled detach/cleanup posture for mod shutdown and uninstall transitions,
  - stronger disabled-mode vanilla restoration in high-impact override families.
- Logging performance hardening:
  - global switch "EnableGlobalBuffer" controls runtime buffering behavior,
  - prealloc guard policy applied across broad "Log.Write(...)" textual callsite families (hundreds of callbacks/callsites across touched modules).
- Build and parser efficiency wave:
  - "WooHooStage" loaded-package cache ("__loadedPackages") to avoid repeated package work,
  - load microprofiler stages ("woohoo_load.*") for targeted bottleneck tracing,
  - parser-level micro-optimizations and safer repeated-parse behavior.
- Practical release objective:
  - reduce overhead/noise on long sessions,
  - keep diagnostics available when enabled,
  - preserve stability-first defaults in normal gameplay.

------------------------------------------------------------
66) Public release alignment addendum (complete user-facing coverage)
------------------------------------------------------------

Kinky Traits overhaul (explicit user-facing scope):
- Kinky Traits were moved out of vanilla CAS/Simology ownership into the dedicated KW trait flow.
- Active management and visibility were aligned to the Skill/traits-side KW UI workflow, including dedicated viewer/editor behavior.
- Investigation/reveal flow for other Sims remains supported in the renewed traits UX path.
- Trait descriptions/benefits/icon consistency was improved where missing or inconsistent.

Debug traits mode (explicit):
- Added/maintained dedicated "DebugTraits" setting for unrestricted traits management behavior in debug-style usage.
- Intended behavior in this mode:
  - reveal/visibility restrictions are relaxed,
  - free trait-change workflow is available without normal gameplay cost gating.

Gender-free all-fours toggle (explicit feature mention):
- Added dedicated setting:
  - "GenderFreeMasturbateOnAllFours"
- Effect:
  - removes male-only trait prerequisite gate for "Masturbate On All Fours" when enabled,
  - keeps normal gating when disabled.
- Menu placement context:
  - exposed in Sex/Animations settings flow.

Bug-fix/misc alignment from public release notes:
- NPC-target interrupt behavior was softened to lighter cancellation posture (CancelByScript-style chain), reducing aggressive cancellation side effects from heavier previous behavior.
- Friendly/Romantic availability regressions from prior builds were restored in the affected branches.
- Known side effect retained in this release line:
  - in some contexts, duplicated visible romantic entries can still appear (for example duplicate "Kiss"/"Flirt") due to EA+KW parallel injection paths.